/*
 * 编写一个简单的进程任务分配程序
 * 目标：使用多条管道+多进程实现不同进程间的随机任务分配（V1.0 版本）
 */

#include <iostream>
#include <vector>
#include <cassert>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include "Task.hpp"
//#include "BitTask.hpp"

using namespace std;

int gnum = 3; // 全局变量，待构建的管道及子进程数

// 任务终端类
class TaskTerm
{
    // 任务终端，包含运行任务所需要的子进程 pid 和 写端 fd
public:
    pid_t _child_id;
    int _write_fd;

    TaskTerm(pid_t id = pid_t(), int fd = int())
        : _child_id(id), _write_fd(fd)
    {
    }

    ~TaskTerm()
    {}
};


void WaitCommand()
{
    while (true)
    {
        int command = 0; // 任务编号
        int n = read(0, &command, sizeof(int));

        if (n == sizeof(int))
        {
            // 指令读取成功
            Task().Execute(command);
        }
        else
        {
            // 指令读取失败
            break; // 退出循环，子进程终止运行
        }
    }
}

void CreateProcess(vector<TaskTerm> &task_term)
{
    for (int i = 0; i < gnum; i++)
    {
        int pipefd[2] = {0};    // 存储读写端fd信息的数组
        int ret = pipe(pipefd); // 创建管道
        assert(ret == 0);
        (void)ret;

        // 0-读端，1-写端

        // 创建子进程，子进程只使用管道读端
        pid_t id = fork();
        assert(id != -1);
        (void)id;

        if (id == 0)
        {
            close(pipefd[1]); // 关闭写端

            dup2(pipefd[0], 0); // 读端重定向为标准输入

            WaitCommand(); // 子进程等待命令

            close(pipefd[0]);
            exit(0);
        }

        close(pipefd[0]); // 父进程关闭读端，与子进程构成通信

        task_term.push_back(TaskTerm(id, pipefd[1])); // 将任务插入任务列表
    }
}

int main()
{
    vector<TaskTerm> task_term;

    // 1、创建五条管道和五个子进程，建立对应的读写关系
    CreateProcess(task_term);

    srand((size_t)time(NULL));
    while (true)
    {
        // 2、选择任务（指定）
        int command = COMMAND_LOG;

        // 3、选择进程执行任务（随机）
        int index = rand() % task_term.size();

        // 4、执行任务，将任务指令 index 写给管道及其子进程
        write(task_term[index]._write_fd, &command, sizeof(command));

        sleep(1);
    }
    
    return 0;
}